package routil

import (
	"github.com/shopspring/decimal"
	"github.com/tidwall/gjson"
	"wzgames/internal/model/roulettep"
	"wzgames/internal/secure/rng"
	"wzgames/pkg/utils/calcutil"
	"wzgames/pkg/utils/stringutil"
)

// 新轮盘工具

type RouUtil struct {
}

// AnalysisChips 分析投注数据
func (gf *RouUtil) AnalysisChips(chips string, config *roulettep.RouletteGameConfig) ([]*roulettep.RouletteChip, int64, bool) {
	var chipsArr []*roulettep.RouletteChip
	ok := true
	result := gjson.Parse(chips)
	var total int64 = 0
	result.ForEach(func(key, value gjson.Result) bool {
		amt := value.Int()
		if amt == 0 {
			ok = false
			return false
		}
		var sector string
		var idx string
		switch key.Str {
		case roulettep.RouBlack:
			if amt < config.Black.Min || amt > config.Black.Max {
				ok = false
				return false
			}
			sector = roulettep.RouBlack
		case roulettep.RouGreen:
			if amt < config.Green.Min || amt > config.Green.Max {
				ok = false
				return false
			}
			sector = roulettep.RouGreen
		case roulettep.RouRed:
			if amt < config.Red.Min || amt > config.Red.Max {
				ok = false
				return false
			}
			sector = roulettep.RouRed
		case roulettep.RouA1:
			if amt < config.A1.Min || amt > config.A1.Max {
				ok = false
				return false
			}
			sector = roulettep.RouA1
		case roulettep.RouA2:
			if amt < config.A2.Min || amt > config.A2.Max {
				ok = false
				return false
			}
			sector = roulettep.RouA2
		case roulettep.RouA3:
			if amt < config.A3.Min || amt > config.A3.Max {
				ok = false
				return false
			}
			sector = roulettep.RouA3
		case roulettep.RouA4:
			if amt < config.A4.Min || amt > config.A4.Max {
				ok = false
				return false
			}
			sector = roulettep.RouA4
		default:
			k := key.Str[:1]
			idx = key.Str[1:]
			idxN, _ := stringutil.ToInt32(idx, 0)
			switch k {
			case roulettep.RouN:
				if amt < config.N.Min || amt > config.N.Max || idx != roulettep.RouZero && idx != roulettep.RouZero1 && (idxN < 1 || idxN > 36) {
					ok = false
					return false
				}
				sector = roulettep.RouN
			default:
				ok = false
				return false
			}
		}
		chipsArr = append(chipsArr, &roulettep.RouletteChip{Key: key.Str, BetAmt: amt, Sector: sector, Tag: idx})
		total += amt

		return true
	})

	if total < config.Total.Min || total > config.Total.Max {
		ok = false
	}

	return chipsArr, total, ok
}

// CalcMultiplier 计算投注额和派彩额
func (gf *RouUtil) CalcMultiplier(config *roulettep.RouletteGameConfig, chipsArr []*roulettep.RouletteChip, retNum, retColor, retGrp string) (decimal.Decimal, decimal.Decimal) {
	l := len(chipsArr)
	betTotal := decimal.NewFromFloat(0.0)
	totalPay := decimal.NewFromFloat(0.0)
	fee := (decimal.NewFromInt(100).Sub(decimal.NewFromFloat(config.Rate))).Div(calcutil.BaseCoefficient)
	chipEquals := decimal.NewFromFloat(config.ChipEquals)
	for i := 0; i < l; i++ {
		chip := chipsArr[i]
		d := decimal.NewFromInt(chip.BetAmt).Mul(fee).Mul(chipEquals)
		betTotal = betTotal.Add(d)
		switch chip.Sector {
		case roulettep.RouBlack:
			if retColor == roulettep.RouBlack {
				totalPay = totalPay.Add(d.Mul(decimal.NewFromFloat(config.Black.Odds)))
			}
		case roulettep.RouGreen:
			if retColor == roulettep.RouGreen {
				totalPay = totalPay.Add(d.Mul(decimal.NewFromFloat(config.Green.Odds)))
			}
		case roulettep.RouRed:
			if retColor == roulettep.RouRed {
				totalPay = totalPay.Add(d.Mul(decimal.NewFromFloat(config.Red.Odds)))
			}
		case roulettep.RouA1:
			if retGrp == roulettep.RouA1 {
				totalPay = totalPay.Add(d.Mul(decimal.NewFromFloat(config.A1.Odds)))
			}
		case roulettep.RouA2:
			if retGrp == roulettep.RouA2 {
				totalPay = totalPay.Add(d.Mul(decimal.NewFromFloat(config.A2.Odds)))
			}
		case roulettep.RouA3:
			if retGrp == roulettep.RouA3 {
				totalPay = totalPay.Add(d.Mul(decimal.NewFromFloat(config.A3.Odds)))
			}
		case roulettep.RouA4:
			if retGrp == roulettep.RouA4 {
				totalPay = totalPay.Add(d.Mul(decimal.NewFromFloat(config.A4.Odds)))
			}
		case roulettep.RouN:
			if retNum == chip.Tag {
				totalPay = totalPay.Add(d.Mul(decimal.NewFromFloat(config.N.Odds)))
			}
		}
	}

	return betTotal, totalPay
}

// Draw 新轮盘开奖结果
func (gf *RouUtil) Draw(servSeed, clientSeeds string, cfg *roulettep.RouletteGameConfig) (string, string, string, string) {
	nums, h512 := rng.CalculateHashWithRoundAndRetHash(servSeed, clientSeeds, 4, 1, 0)
	// 见新轮盘游戏实例配置
	l := int32(len(cfg.Items))
	v1 := decimal.NewFromFloat(nums[0]).Mul(decimal.NewFromInt32(l))
	idx := int32(v1.IntPart())
	if idx >= l {
		idx = l - 1
	}
	tag := cfg.Items[idx]
	var color, grp string
	if gf.checkHit(tag, cfg.Black.Nums.Vals) {
		color = roulettep.RouBlack
	} else if gf.checkHit(tag, cfg.Green.Nums.Vals) {
		color = roulettep.RouGreen
	} else if gf.checkHit(tag, cfg.Red.Nums.Vals) {
		color = roulettep.RouRed
	}
	if gf.checkHit(tag, cfg.A1.Nums.Vals) {
		grp = roulettep.RouA1
	} else if gf.checkHit(tag, cfg.A2.Nums.Vals) {
		grp = roulettep.RouA2
	} else if gf.checkHit(tag, cfg.A3.Nums.Vals) {
		grp = roulettep.RouA3
	} else if gf.checkHit(tag, cfg.A4.Nums.Vals) {
		grp = roulettep.RouA4
	}
	return h512, tag, color, grp
}

func (gf *RouUtil) checkHit(retNum string, nums []string) bool {
	for i := 0; i < len(nums); i++ {
		if nums[i] == retNum {
			return true
		}
	}

	return false
}
